/*
 * Copyright (C) 2019-2020 Alibaba Group Holding Limited
 */

/******************************************************************************
 * @file     board_init.c
 * @brief    CSI Source File for board init
 * @version  V1.0
 * @date     31. June 2018
 ******************************************************************************/

#include <stdio.h>
#include <stdint.h>

#include <soc.h>
#include <csi_core.h>
// #include <yun_mpu.h>
#include <csi_core.h>
#include <io.h>

#include <pin.h>
#include <drv/usart.h>

static usart_handle_t g_console_handle = NULL;
extern int g_tick_cnt;

static void board_pinmux_config(void)
{
    //console
    drv_pinmux_config(CONSOLE_TXD, CONSOLE_TXD_FUNC);
    drv_pinmux_config(CONSOLE_RXD, CONSOLE_RXD_FUNC);
}
#ifdef CONFIG_SYSTEM_SECURE
static void __memcpy(void *dest, const void *src, size_t n)
{
    int i;

    for (i = 0; i < n; i++) {
        *((uint8_t *)dest + i) = *((uint8_t *)src + i);
    }
}
#endif
extern void Reset_Handler(void);

static void section_data_copy(void)
{
#ifdef CONFIG_SYSTEM_SECURE
    extern uint32_t __stext;
    extern uint32_t __etext;
    extern uint32_t __srodata;
    extern uint32_t __flash_code_end__;
    extern uint32_t __erodata;
    extern uint32_t __data_start__;
    extern uint32_t __data_end__;
    extern uint32_t __ram_code_start__;
    extern uint32_t __ram_code_end__;

    uint32_t src_addr;

    uint32_t xip_flag = (uint32_t)&__stext;

    /* if run in flash */
    if ((xip_flag & 0xFF000000) == 0x8000000) {
        src_addr = (uint32_t)&__erodata;
        __memcpy((void *)(&__data_start__), \
                 (void *)src_addr, \
                 (uint32_t)(&__data_end__) - (uint32_t)(&__data_start__));

        src_addr += (uint32_t)(&__data_end__) - (uint32_t)(&__data_start__);
        __memcpy((void *)(&__ram_code_start__), \
                 (void *)src_addr, \
                 (uint32_t)(&__ram_code_end__) - (uint32_t)(&__ram_code_start__));
    } else {
        uint32_t entry_addr = (uint32_t)&Reset_Handler;

        /* if reset_handler run in flash */
        if ((entry_addr & 0xFF000000) == 0x8000000) {
            src_addr = (uint32_t)&__flash_code_end__;
            __memcpy((void *)(&__stext), \
                     (void *)src_addr, \
                     (uint32_t)(&__etext) - (uint32_t)(&__stext));

            src_addr += (uint32_t)(&__etext) - (uint32_t)(&__stext);
            __memcpy((void *)(&__srodata), \
                     (void *)src_addr, \
                     (uint32_t)(&__erodata) - (uint32_t)(&__srodata));

            src_addr += (uint32_t)(&__erodata) - (uint32_t)(&__srodata);
            __memcpy((void *)(&__data_start__), \
                     (void *)src_addr, \
                     (uint32_t)(&__data_end__) - (uint32_t)(&__data_start__));

            src_addr += (uint32_t)(&__data_end__) - (uint32_t)(&__data_start__);
            __memcpy((void *)(&__ram_code_start__), \
                     (void *)src_addr, \
                     (uint32_t)(&__ram_code_end__) - (uint32_t)(&__ram_code_start__));
        }
    }

#endif
}

static void config_irq_priority(void)
{
    int i;

    for (i = 1; i <= 51; i++) {
        csi_vic_set_prio(i, 1);
    }

    csi_vic_set_prio(DMAC1_IRQn, 0);
}

static void _system_init_for_baremetal(void)
{
    __enable_excp_irq();

    csi_coret_config(drv_get_cpu_freq(0) / CONFIG_SYSTICK_HZ, CORET_IRQn);    //10ms

    // mm_heap_initialize();
}

uint32_t g_prim_vbr;
extern uint32_t __Vectors[];
void SystemInit(void)
{
    g_tick_cnt = 0;
    section_data_copy();
    // g_prim_vbr = __get_VBR();
    __set_VBR((uint32_t) & (__Vectors));

    /* Clear active and pending IRQ, and disable IRQ */
    // VIC->IABR[0] = 0x0;
    // VIC->ICPR[0] = 0xFFFFFFFF;
    // VIC->ICER[0] = 0xFFFFFFFF;

    // /* config APB1 clock from 18M to 48M */
    // putreg32(2, (uint32_t *)0x8b000004);

    // csi_cache_set_range(0, 0x18000000, CACHE_CRCR_16M, 1);
    // csi_icache_enable();
    // csi_dcache_enable();

    config_irq_priority();
    // config_system_clock();
    drv_clk_enable(UART1_CLK);
    _system_init_for_baremetal();
}

void app_uart_init(void)
{
    board_pinmux_config();

    /* init the console */
    g_console_handle = csi_usart_initialize(CONSOLE_IDX, NULL);
    /* config the UART */
    csi_usart_config(g_console_handle, 115200, USART_MODE_ASYNCHRONOUS, USART_PARITY_NONE, USART_STOP_BITS_1, USART_DATA_BITS_8);
}

void board_init(void)
{
    app_uart_init();
}

int fputc(int ch, FILE *stream)
{
    if (g_console_handle == NULL) {
        return -1;
    }

    if (ch == '\n') {
        csi_usart_putchar(g_console_handle, '\r');
    }

    csi_usart_putchar(g_console_handle, ch);

    return 0;
}
